package com.hisense.ovcloud.apicontrol.service;

import com.hisense.ovcloud.apicontrol.client.JulinkPsClient;
import com.hisense.ovcloud.apicontrol.config.Constants;
import com.hisense.ovcloud.apicontrol.dto.req.ValidateReq;
import com.hisense.ovcloud.apicontrol.dto.req.VerifyReq;
import com.hisense.ovcloud.apicontrol.dto.resp.TokenRes;
import com.hisense.ovcloud.apicontrol.errors.ResForGW;
import com.hisense.ovcloud.apicontrol.errors.SystemError;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Service
public class ApplianceTokenCheckService extends BaseAGService {
    @Value("${appliance.token.auth.endpoints:/wine-appliance/,/deviceauth/}")
    private String applianceTokenAuthEndpoint;

    private final JulinkPsClient psClient;

    public ApplianceTokenCheckService(JulinkPsClient psClient) {
        this.psClient = psClient;
    }

    public boolean shouldFilter(ValidateReq req) {
        return Arrays.stream(applianceTokenAuthEndpoint.split(",")).anyMatch(req.getPath()::contains);
    }

    public Mono<ResForGW> run(ValidateReq r, LinkedHashMap<String, Object> parametersMap) {
        if (!shouldFilter(r)) {
            return Mono.just(ResForGW.builder().build());
        }

        ResForGW res = ResForGW.builder().build();
        if (parametersMap.isEmpty()) {
            return Mono.just(setErrorResponse(res, SystemError.MISSPARAM));
        }

        Object token = parametersMap.get(Constants.PARAM_TOKEN);
        if (token == null) {
            return Mono.just(setErrorResponse(res,
                    SystemError.PARAMINVALID.getError(Constants.PARAM_TOKEN)));
        }

        String accessToken = token.toString();
        return psClient.verify(VerifyReq.builder().token(accessToken).build())
                .flatMap(verifyRes -> {
                    log.info("verifyRes:{}", verifyRes);
                    if (verifyRes.getCode() != Constants.RESULT_CODE_SUCCESS) {
                        setErrorResponse(res,
                                SystemError.ACCESSTOKENPARSEERROR);
                    } else {
                        Map<String, Object> insertMaps = new HashMap<>();
                        insertMaps.put(Constants.PARAM_WIFIID_TOKEN, ((LinkedHashMap) (verifyRes.getData())).get("wifi_id"));
                        insertMaps.put(Constants.PARAM_WIFIID, ((LinkedHashMap) (verifyRes.getData())).get("wifi_id"));
                        res.setData(insertMaps);
                    }
                    return Mono.just(res);
                })
                .onErrorResume(ex -> {
                    log.error("verify token {} failed! res: {}", accessToken, ex.getMessage());
                    return Mono.just(setErrorResponse(res,
                            SystemError.SYSERROR));
                });
    }

    public Mono<TokenRes> tokenAuth(String accessToken){
        Map<String, Object> insertMaps = new HashMap<>();
        return psClient.verify(VerifyReq.builder().token(accessToken).build())
                .flatMap(verifyRes -> {
                    log.info("verifyRes:{}", verifyRes);
                    if (verifyRes.getCode() == Constants.RESULT_CODE_SUCCESS) {
                        insertMaps.put(Constants.PARAM_WIFIID_TOKEN, ((LinkedHashMap) (verifyRes.getData())).get("wifi_id"));
                        insertMaps.put(Constants.PARAM_WIFIID, ((LinkedHashMap) (verifyRes.getData())).get("wifi_id"));
                    }

                    return Mono.just(TokenRes.builder().insertMaps(insertMaps).isValid(true).build());
                })
                .onErrorResume(ex -> {
                    log.error("tokenAuth {} failed! res: {}", accessToken, ex.getMessage());
                    return Mono.just(TokenRes.builder().build());
                });
    }

}
